library(mosaic)
library(tidyverse)
library(lubridate)
library(DataComputing)
library(rvest)
library(broom)
library(rworldmap)

Research Focus:

As COVID-19 spreads at an alarming rate, a pressing question at a global scale emerges– what factors of a country contribute to the spread of Coronavirus. We hope to analyze the relationship between a country’s population level, population density, and continent categorization on the spread of COVID-19.

Data Access

Reading in the Data:

Data Source 1: COVID

COVID <- read.csv(file = "total-covid-cases-deaths-per-million.csv")
COVID
COVID %>%
  nrow()
[1] 9487
COVID %>%
  names()
  [1] "total.covid.cases.deaths.per.million" "X"                                    "X.1"                                 
  [4] "X.2"                                  "X.3"                                  "X.4"                                 
  [7] "X.5"                                  "X.6"                                  "X.7"                                 
 [10] "X.8"                                  "X.9"                                  "X.10"                                
 [13] "X.11"                                 "X.12"                                 "X.13"                                
 [16] "X.14"                                 "X.15"                                 "X.16"                                
 [19] "X.17"                                 "X.18"                                 "X.19"                                
 [22] "X.20"                                 "X.21"                                 "X.22"                                
 [25] "X.23"                                 "X.24"                                 "X.25"                                
 [28] "X.26"                                 "X.27"                                 "X.28"                                
 [31] "X.29"                                 "X.30"                                 "X.31"                                
 [34] "X.32"                                 "X.33"                                 "X.34"                                
 [37] "X.35"                                 "X.36"                                 "X.37"                                
 [40] "X.38"                                 "X.39"                                 "X.40"                                
 [43] "X.41"                                 "X.42"                                 "X.43"                                
 [46] "X.44"                                 "X.45"                                 "X.46"                                
 [49] "X.47"                                 "X.48"                                 "X.49"                                
 [52] "X.50"                                 "X.51"                                 "X.52"                                
 [55] "X.53"                                 "X.54"                                 "X.55"                                
 [58] "X.56"                                 "X.57"                                 "X.58"                                
 [61] "X.59"                                 "X.60"                                 "X.61"                                
 [64] "X.62"                                 "X.63"                                 "X.64"                                
 [67] "X.65"                                 "X.66"                                 "X.67"                                
 [70] "X.68"                                 "X.69"                                 "X.70"                                
 [73] "X.71"                                 "X.72"                                 "X.73"                                
 [76] "X.74"                                 "X.75"                                 "X.76"                                
 [79] "X.77"                                 "X.78"                                 "X.79"                                
 [82] "X.80"                                 "X.81"                                 "X.82"                                
 [85] "X.83"                                 "X.84"                                 "X.85"                                
 [88] "X.86"                                 "X.87"                                 "X.88"                                
 [91] "X.89"                                 "X.90"                                 "X.91"                                
 [94] "X.92"                                 "X.93"                                 "X.94"                                
 [97] "X.95"                                 "X.96"                                 "X.97"                                
[100] "X.98"                                 "X.99"                                 "X.100"                               
[103] "X.101"                                "X.102"                                "X.103"                               
[106] "X.104"                                "X.105"                                "X.106"                               
[109] "X.107"                                "X.108"                                "X.109"                               
[112] "X.110"                                "X.111"                                "X.112"                               
[115] "X.113"                                "X.114"                                "X.115"                               
[118] "X.116"                                "X.117"                                "X.118"                               
[121] "X.119"                                "X.120"                                "X.121"                               
[124] "X.122"                                "X.123"                                "X.124"                               
[127] "X.125"                                "X.126"                                "X.127"                               
[130] "X.128"                                "X.129"                                "X.130"                               
[133] "X.131"                                "X.132"                                "X.133"                               
[136] "X.134"                                "X.135"                                "X.136"                               
[139] "X.137"                                "X.138"                                "X.139"                               
[142] "X.140"                                "X.141"                                "X.142"                               
[145] "X.143"                                "X.144"                                "X.145"                               
[148] "X.146"                                "X.147"                                "X.148"                               
[151] "X.149"                                "X.150"                                "X.151"                               
[154] "X.152"                                "X.153"                                "X.154"                               
[157] "X.155"                                "X.156"                                "X.157"                               
[160] "X.158"                                "X.159"                                "X.160"                               
[163] "X.161"                                "X.162"                                "X.163"                               
[166] "X.164"                                "X.165"                                "X.166"                               
[169] "X.167"                                "X.168"                                "X.169"                               
[172] "X.170"                                "X.171"                                "X.172"                               
[175] "X.173"                                "X.174"                                "X.175"                               
[178] "X.176"                                "X.177"                                "X.178"                               
[181] "X.179"                                "X.180"                                "X.181"                               
[184] "X.182"                                "X.183"                                "X.184"                               
[187] "X.185"                                "X.186"                                "X.187"                               
[190] "X.188"                                "X.189"                                "X.190"                               
[193] "X.191"                                "X.192"                                "X.193"                               
[196] "X.194"                                "X.195"                                "X.196"                               
[199] "X.197"                                "X.198"                                "X.199"                               
[202] "X.200"                                "X.201"                                "X.202"                               
[205] "X.203"                                "X.204"                                "X.205"                               
[208] "X.206"                                "X.207"                                "X.208"                               
[211] "X.209"                                "X.210"                                "X.211"                               
[214] "X.212"                                "X.213"                                "X.214"                               
[217] "X.215"                                "X.216"                                "X.217"                               
[220] "X.218"                                "X.219"                                "X.220"                               
[223] "X.221"                                "X.222"                                "X.223"                               
[226] "X.224"                                "X.225"                                "X.226"                               
[229] "X.227"                                "X.228"                                "X.229"                               
[232] "X.230"                                "X.231"                                "X.232"                               
[235] "X.233"                                "X.234"                                "X.235"                               
[238] "X.236"                                "X.237"                                "X.238"                               
[241] "X.239"                                "X.240"                                "X.241"                               
[244] "X.242"                                "X.243"                                "X.244"                               
[247] "X.245"                                "X.246"                                "X.247"                               
[250] "X.248"                                "X.249"                                "X.250"                               
[253] "X.251"                                "X.252"                                "X.253"                               
[256] "X.254"                               
COVID %>%
  head()

The original COVID data set is clearly in need of some data wrangling– it has an abundance of empty columns along with improper column headings.

Data Source 2: CountryData

CountryData
CountryData %>%
  nrow()
[1] 256
CountryData %>%
  names()
 [1] "country"           "area"              "pop"               "growth"            "birth"             "death"            
 [7] "migr"              "maternal"          "infant"            "life"              "fert"              "health"           
[13] "HIVrate"           "HIVpeople"         "HIVdeath"          "obesity"           "underweight"       "educ"             
[19] "unemploymentYouth" "GDP"               "GDPgrowth"         "GDPcapita"         "saving"            "indProd"          
[25] "labor"             "unemployment"      "family"            "tax"               "budget"            "debt"             
[31] "inflation"         "discount"          "lending"           "narrow"            "broad"             "credit"           
[37] "shares"            "balance"           "exports"           "imports"           "gold"              "externalDebt"     
[43] "homeStock"         "abroadStock"       "elecProd"          "elecCons"          "elecExp"           "elecImp"          
[49] "elecCap"           "elecFossil"        "elecNuc"           "elecHydro"         "elecRenew"         "oilProd"          
[55] "oilExp"            "oilImp"            "oilRes"            "petroProd"         "petroCons"         "petroExp"         
[61] "petroImp"          "gasProd"           "gasCons"           "gasExp"            "gasImp"            "gasRes"           
[67] "mainlines"         "cell"              "netHosts"          "netUsers"          "airports"          "railways"         
[73] "roadways"          "waterways"         "marine"            "military"         
CountryData %>%
  head()

CountryData is tidy, but in its current form, it contains many variables nonrelevant to our analysis– we will extract the relevant factors (country, area, pop).

Data Source 3: countryRegions

countryRegions
countryRegions %>%
  nrow()
[1] 254
countryRegions %>%
  names()
 [1] "ISO3"         "ADMIN"        "REGION"       "continent"    "GEO3major"    "GEO3"         "IMAGE24"      "GLOCAF"      
 [9] "Stern"        "SRESmajor"    "SRES"         "GBD"          "AVOIDnumeric" "AVOIDname"    "LDC"          "SID"         
[17] "LLDC"        
countryRegions %>%
  head()

The countryRegions data set is tidy, but it contains many variables nonrelevant to our analysis– we will extract the relevant factors (ISO3, REGION).

Data Wrangling

Tidying the COVID Dataset

COVID

Since our analysis is focused on the spread of COVID-19, we select only columns which pertain to the number of COVID-19 cases in countries over time. We rename to columns to descriptive titles, and we convert values to usable form.

TidyCOVID <- COVID %>%
  rename(country = total.covid.cases.deaths.per.million ) %>%
  rename( code = X ) %>%
  rename(date = X.1 ) %>%
  rename(casesPerMillion = X.3) %>%
  filter(row_number() > 1) %>%
  subset(select = c(1,2,3,5)) %>%
  mutate( country = as.character(country) ) %>%  
  mutate( code = as.character(code) ) %>%
  mutate(date = mdy(date)) %>%
  mutate(casesPerMillion = as.integer(casesPerMillion) - 1)

The Tidy COVID dataset for our analysis.

TidyCOVID

Each instance in TidyCOVID represents a different day in a country’s progression through COVID-19. It provides the country code (which will be later utilized to assign continent categorization), the date, and the total cases per million up at that date.

Wrangling of countryRegions Dataset

We will extract the ISO3 country code and continent from the countryRegions data. Since naming conventions of countries is variate, the ISO3 country code allows us a standardized demarcation of country with which to join with other data tables.

Labels <-
  countryRegions %>%
  subset(select = c("ISO3", "REGION")) %>%
  rename(continent = REGION)
Labels

Data Extraction of CountryData Dataset

We will select the aspects of CountryData relevant to our analysis. These attributes are: area (sq km) and pop (number of people). From these attributes we calculate the country’s popdensity (person/sq km).

RelevantCountryData <-
  CountryData %>%
  subset(select = c(1,2,3)) %>%
  mutate(popdensity = pop/area)
RelevantCountryData

Joining Data & Relevant Variable Synthesis

At this point, we join the tidied COVID data set with the extracted CountryData set such that each case represents a different day in a country’s progression through COVID-19, providing the specific country, date, total cases per million up at that date, the area of the country (sq km), the population of the country, the population density of the countrym the total number of cases (derived by multiplying a country’s casesPerMillion by the population (in millions)), and the continent categorization.

COVIDGrowth <-
  inner_join(TidyCOVID, RelevantCountryData, by = c("country")) %>%
  mutate("cases" = (casesPerMillion * round(pop/1000000, digits = 0)))
COVIDGrowth <-
  COVIDGrowth %>%
  left_join(Labels, by = c("code" = "ISO3"))
COVIDGrowth <-
  COVIDGrowth %>%
  subset(select = c(1, 3, 4, 5, 6, 7, 8, 9))
COVIDGrowth

Creation of new Data Table: FirstInstance

This new data table records the first date that a country recorded a nonzero number of COVID-19 cases. This datagraph will help us visualize when countries first became infected.

FirstInstance <-
  COVIDGrowth %>%
  filter(cases != 0) %>%
  group_by(country, continent) %>%
  summarise(beginningofspread = min(date))
  
FirstInstance

Creation of new Data Table: DailySpread

The DailySpread data frame utilizes the COVIDGrowth data along with the beginningofspread variable (which was derived in the FirstInstance table) in order to calculate a straight-line approximation of the daily spread of COVID-19, averaging cases over time from the first day a country was infected to the most recent date in the data table (April 5 2020). If a country has not been infected, the dailyspread is set to 0.

DailySpread <-
  left_join(COVIDGrowth, FirstInstance, by = c("country")) %>%
  filter(date == "2020-04-05") %>%
  mutate(dayselapsed = date - beginningofspread) %>%
  mutate(dailyspread = cases / as.numeric(dayselapsed) ) %>%
  mutate(dailyspreadpermillion = casesPerMillion / as.numeric(dayselapsed) ) %>%
  subset(select = c("country", "beginningofspread", "dailyspread", "dailyspreadpermillion"))
DailySpread$dailyspread[is.na(DailySpread$dailyspread)] <- 0
DailySpread$dailyspreadpermillion[is.na(DailySpread$dailyspreadpermillion)] <- 0
DailySpread

Comprehensive Data Table: COVIDFinal

Joining the growth-calculated COVID data set with the DailySpread statistics allows us our comprehensive data frame with which we will conduct our analysis. Within this frame, each case represents a different day in a country’s progression through COVID-19, providing the specific country, date, total cases per million up at that date, the area of the country (sq km), the population of the country, the population density of the countrym the total number of cases (derived by multiplying a country’s casesPerMillion by the population (in millions)), continent categorization, date which the spread of COVID-19 began, the average daily spread of COVID-19, and the average daily spread of COVID-19 per million of population.

COVIDFinal <-
  left_join(COVIDGrowth, DailySpread, by = c("country"))
COVIDFinal

Data Visualization

Overall Growth of COVID-19 Over Time

COVIDFinal %>%
  group_by(date) %>%
  summarise(totalcases = sum(cases)) %>%
  ggplot(aes(x = date, y = totalcases)) + 
  geom_point() +
  xlab("Date") +
  ylab("COVID-19 Cases")

This graph demonstrates the exponential growth trend of COVID-19 globally. There is a strong positive correlation between the progression of time and then number of COVID-19 cases worldwide.

Continental Growth of COVID-19 Over Time

na.omit(COVIDFinal) %>%
  group_by(date, continent) %>%
  summarise(totalcases = sum(cases)) %>%
  ggplot(aes(x = date, y = totalcases)) + 
  geom_point() +
  facet_wrap(~continent) +
  xlab("Date") +
  ylab("COVID-19 Cases")

This graph shows the growth of COVID-19 cases over time, faceted by continent. The global exponential trend is most visible in the origin continent of Asia, but the positive correlation of COVID-19 over time is visible in each continents.

Infection of COVID-19 into countries over time

na.omit(FirstInstance) %>%
  ggplot(aes(x = beginningofspread, fill = continent)) +
  geom_dotplot(stackgroups = TRUE, binwidth = 1, binpositions="all") +
  xlab("Country's First Case of COVID-19") +
  theme(panel.background = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.title.y = element_blank())

This graph shows the progression of the COVID-19 spread across continents. As supported and congruent with the faceted graph of continental growth over time, Asia was the first continent to be infected, followed by North America and Europe. In late February, South America and Africa began to become infected, and Australia was able to isolate until mid March. Where continental datapoints show density alligns with, in the graphic above, where the continents experience greatest periods of growth.

Which countries have the highest infection rates?

  
COVIDFinal %>%
  group_by(country) %>%
  summarise(dailyspread = mean(dailyspread)) %>%
  arrange(desc(dailyspread)) %>%
  head(20) %>%
  ggplot(aes(x = reorder(country, desc(dailyspread)), y= dailyspread)) +
  geom_bar(stat="identity", position = 'stack', width=.9) +
  theme(axis.text.x=element_text(angle = 60, hjust = 1)) +
  scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
  ylab("Average Number Infected Per Day") +
  theme(axis.title.x = element_blank())

This graphic demonstrates the countries with the highest infection rates– those most significant of which are China, India, Indonesia, and the United States, closely followed by Brazil, after which the rate of infection tapers off to a comparatively similar rate.

Compare this to which countries have the highest populations

COVIDFinal %>%
  group_by(country) %>%
  summarise(pop = mean(pop)) %>%
  arrange(desc(pop)) %>%
  head(20) %>%
  ggplot(aes(x = reorder(country, desc(pop)), y= pop)) +
  geom_bar(stat="identity", position = 'stack', width=.9) +
  theme(axis.text.x=element_text(angle = 60, hjust = 1)) +
  scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
  ylab("Population") +
  theme(axis.title.x = element_blank())

We see a similar trend here, in that the countries of top population (in slightly different order) consist of China, India, Indonesia, the United States, and closely trailing Brazil, after which population seems to taper off to relatively similar levels.

Let’s visualize the relationship between population and COVID-19 spread on the same data frame… with an awareness of the continental distribution

na.omit(COVIDFinal) %>%
  ggplot(aes(x = pop, y = dailyspread, color = continent)) + 
  geom_point() +
  xlab("Population of Country") +
  ylab("Average Number Infected Per Day")

This dataframe clearly demonstrates the strong positive correlation between a country’s population and average number infected per day, as supported by our analysis of the previous two graphics. While most countries of the world trail with under 10,000 infected per day, the 5 countries with the highest popualtion in the data set have over 15,000 - up to over 50,000- and are far separated from the rest of the pack. Population, while not a direct factor contributing to the level of development of a country, is a decent indicator of the rate of infection.

Does the relationship hold up after removing the largest outliers (China and India)?

Does the positive relationship hold up across all continents?

na.omit(COVIDFinal) %>%
  ggplot(aes(x = pop, y = dailyspread, color = continent)) + 
  geom_point() +
  xlim(0,500000000) +
  ylim(0, 40000) +
  xlab("Population of Country") +
  ylab("Average Number Infected Per Day") +
  stat_smooth(method = lm) 

Removing the largest outliers of population and number infected, the poitive relationship between average number infected and population still holds; for each continent, the trends are very clearly upward sloping.

A prevailing explanation for the spread of COVID-19 is social closeness, therefore, we hypothesize that countries with the highest population density will have the highest proportional rates of infection. To measure the proportional rates of infection, it is essential to use a standardized metric, such that the data is not skewed towards the countries with simply the most people. Therefore, we will analyze the variable “population per million infected per day”, which captures a representation of the percentage of a country’s population that is effective. If our hypothesis is correct, the countries with the highest population per million infected per day will be those with the highest population density.

Which countries have the highest infection rates per million?

  
COVIDFinal %>%
  group_by(country) %>%
  summarise(dailyspreadpermillion = mean(dailyspreadpermillion)) %>%
  arrange(desc(dailyspreadpermillion)) %>%
  head(20) %>%
  ggplot(aes(x = reorder(country, desc(dailyspreadpermillion)), y= dailyspreadpermillion)) +
  geom_bar(stat="identity", position = 'stack', width=.9) +
  theme(axis.text.x=element_text(angle = 60, hjust = 1)) +
  scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
  ylab("Population Per Million Infected Per Day") +
  theme(axis.title.x = element_blank())

According the this graph, those with the highest infection rates with the confounding factor of population removed (since it is population per million, it has been adjusted to put all countries on one scale) are Guinea-Bissau, Botswana, Eritrea, El Salvador, and Puerto Rico.

Which countries have the highest population density?

  
COVIDFinal %>%
  group_by(country) %>%
  summarise(popdensity = mean(popdensity)) %>%
  arrange(desc(popdensity)) %>%
  head(20) %>%
  ggplot(aes(x = reorder(country, desc(popdensity)), y= popdensity)) +
  geom_bar(stat="identity", position = 'stack', width=.9) +
  theme(axis.text.x=element_text(angle = 60, hjust = 1)) +
  scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
  ylab("Population Density (people/sq km)") +
  theme(axis.title.x = element_blank())

According the this graph, those with the highest population density (number of people per square kilometer) are Monaco, Singapore, and Gibraltar.

Is there a visible correlation between these attributes?

na.omit(COVIDFinal) %>%
  ggplot(aes(x = popdensity, y = dailyspreadpermillion)) +
  geom_point() 

On this graph, it is chalenging to see a clear relationship between population density and daily spread of COVID-19 per million. For the sake of comprehensive analysis, we will further divide the information.

What if faceted by continent?

na.omit(COVIDFinal) %>%
  ggplot(aes(x = popdensity, y = dailyspreadpermillion)) +
  geom_point() + 
  facet_wrap(~continent) + 
  xlim(0,1500)

Again, it is hard to see a perfect correlaiton here. In general, all the graphs show little to no correlation between the population density and the daily spread per million.

Extended Comparative Analysis - Country Comparison Function

Easy to Traverse– Wide Countries

WideCountries <-
  COVIDFinal %>%
  subset(select = c("country", "date", "cases")) %>%
  spread(key = date, value = cases)
WideCountries[is.na(WideCountries)] <- 0
WideCountries

compareCOVID() definition

compareCOVID <- function(countryA, countryB) {
  
    A <-
    WideCountries %>%
    filter(country == countryA)
  
  B <-
    WideCountries %>%
    filter(country == countryB)
  A <-
    A %>%
    gather(key = date, value = count) %>%
    filter(row_number() > 1) %>%
    mutate(date = lubridate::ymd(date)) %>%
    mutate(count = as.numeric(count)) %>%
    mutate(country = countryA)
  
  B <-
    B %>%
    gather(key = date, value = count) %>%
    filter(row_number() > 1) %>%
    mutate(date = lubridate::ymd(date))%>%
    mutate(count = as.numeric(count)) %>%
    mutate(country = countryB)
  
  
  GG <-
    rbind(A,B)
  
  return( ggplot(GG, aes(x = date, y = count, color = country)) +
    stat_smooth(formula = y ~ x, method = "loess") +
      ylab("Number of COVID-19 Cases") +
      xlab("Date"))
  
}

Ex. of compareCOVID() in use:

This function allow us to create a direct comparison between two countries based on the date and the number of COVID-19 cases in each country. This way, we can compare the spread between nations and identify similar trends in different parts of the world.

compareCOVID("China", "United States")

compareCOVID("Japan", "Russia")

compareCOVID("Puerto Rico", "Belgium")

Conclusion

Ultimately, the contributing factors of the spread of COVID-19 still remains a mystery to us. We were able to find a strong positive correlation between the population of a country and the spread. This indicates that the more people a country has, the more likely the infection is to affect a large number of people. However, we struggled to find a strong correlation, once standardized and confounding factors were removed, between the population density of a country and its infection rate per million. This does not necessarily prove that density of living does not contribute to the spread of COVID-19– one fault present within this analysis is that population density was calculated from a country’s entire land area, whereas only a small portion of this land area may be inhabited. If we were to conduct this analysis again, we would seek out data which provides the inhabited living area of a country to more accurately calculate population density. Furthermore, as demonstrated by the graphics, many countries have been infected very recently, or not infected at all. The growth of country demonstrates in this short period of time may not be indicative of the overall growth trend that a country experiences. In the future, once we are more updated and more information about COVID-19 is released, some of the trends which we are seeking may be more relevant or easy to define. However, with the data we currently possess, it was not possible to make the conclusion– that population density is correlated with standardized COVID-19 spread– with confidence.

LS0tCnRpdGxlOiAiRmluYWwgUHJvamVjdCIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcnM6ICJKb3NlcGggUGV2bmVyIGFuZCBFdmVseW4gTXVycmF5IgotLS0KCmBgYHtyfQpsaWJyYXJ5KG1vc2FpYykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KERhdGFDb21wdXRpbmcpCmxpYnJhcnkocnZlc3QpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkocndvcmxkbWFwKQpgYGAKCiMjIFJlc2VhcmNoIEZvY3VzOgoKQXMgQ09WSUQtMTkgc3ByZWFkcyBhdCBhbiBhbGFybWluZyByYXRlLCBhIHByZXNzaW5nIHF1ZXN0aW9uIGF0IGEgZ2xvYmFsIHNjYWxlIGVtZXJnZXMtLSB3aGF0IGZhY3RvcnMgb2YgYSBjb3VudHJ5IGNvbnRyaWJ1dGUgdG8gdGhlIHNwcmVhZCBvZiBDb3JvbmF2aXJ1cy4gV2UgaG9wZSB0byBhbmFseXplIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhIGNvdW50cnkncyBwb3B1bGF0aW9uIGxldmVsLCBwb3B1bGF0aW9uIGRlbnNpdHksIGFuZCBjb250aW5lbnQgY2F0ZWdvcml6YXRpb24gb24gdGhlIHNwcmVhZCBvZiBDT1ZJRC0xOS4KCgoKIyMgRGF0YSBBY2Nlc3MKCiMjIyBSZWFkaW5nIGluIHRoZSBEYXRhOgoKCiMjIyMgRGF0YSBTb3VyY2UgMTogQ09WSUQKYGBge3J9CkNPVklEIDwtIHJlYWQuY3N2KGZpbGUgPSAidG90YWwtY292aWQtY2FzZXMtZGVhdGhzLXBlci1taWxsaW9uLmNzdiIpCkNPVklECmBgYAoKYGBge3J9CkNPVklEICU+JQogIG5yb3coKQpgYGAKYGBge3J9CkNPVklEICU+JQogIG5hbWVzKCkKYGBgCmBgYHtyfQpDT1ZJRCAlPiUKICBoZWFkKCkKYGBgCgpUaGUgb3JpZ2luYWwgQ09WSUQgZGF0YSBzZXQgaXMgY2xlYXJseSBpbiBuZWVkIG9mIHNvbWUgZGF0YSB3cmFuZ2xpbmctLSBpdCBoYXMgYW4gYWJ1bmRhbmNlIG9mIGVtcHR5IGNvbHVtbnMgYWxvbmcgd2l0aCBpbXByb3BlciBjb2x1bW4gaGVhZGluZ3MuCgoKIyMjIyBEYXRhIFNvdXJjZSAyOiBDb3VudHJ5RGF0YQpgYGB7cn0KQ291bnRyeURhdGEKYGBgCgpgYGB7cn0KQ291bnRyeURhdGEgJT4lCiAgbnJvdygpCmBgYApgYGB7cn0KQ291bnRyeURhdGEgJT4lCiAgbmFtZXMoKQpgYGAKYGBge3J9CkNvdW50cnlEYXRhICU+JQogIGhlYWQoKQpgYGAKCkNvdW50cnlEYXRhIGlzIHRpZHksIGJ1dCBpbiBpdHMgY3VycmVudCBmb3JtLCBpdCBjb250YWlucyBtYW55IHZhcmlhYmxlcyBub25yZWxldmFudCB0byBvdXIgYW5hbHlzaXMtLSB3ZSB3aWxsIGV4dHJhY3QgdGhlIHJlbGV2YW50IGZhY3RvcnMgKGNvdW50cnksIGFyZWEsIHBvcCkuCgojIyMjIERhdGEgU291cmNlIDM6IGNvdW50cnlSZWdpb25zCgpgYGB7cn0KY291bnRyeVJlZ2lvbnMKYGBgCmBgYHtyfQpjb3VudHJ5UmVnaW9ucyAlPiUKICBucm93KCkKYGBgCmBgYHtyfQpjb3VudHJ5UmVnaW9ucyAlPiUKICBuYW1lcygpCmBgYApgYGB7cn0KY291bnRyeVJlZ2lvbnMgJT4lCiAgaGVhZCgpCmBgYAoKVGhlIGNvdW50cnlSZWdpb25zIGRhdGEgc2V0IGlzIHRpZHksIGJ1dCBpdCBjb250YWlucyBtYW55IHZhcmlhYmxlcyBub25yZWxldmFudCB0byBvdXIgYW5hbHlzaXMtLSB3ZSB3aWxsIGV4dHJhY3QgdGhlIHJlbGV2YW50IGZhY3RvcnMgKElTTzMsIFJFR0lPTikuCgoKIyMgRGF0YSBXcmFuZ2xpbmcKCiMjIyBUaWR5aW5nIHRoZSBDT1ZJRCBEYXRhc2V0CgpgYGB7cn0KQ09WSUQKYGBgCgpTaW5jZSBvdXIgYW5hbHlzaXMgaXMgZm9jdXNlZCBvbiB0aGUgc3ByZWFkIG9mIENPVklELTE5LCB3ZSBzZWxlY3Qgb25seSBjb2x1bW5zIHdoaWNoIHBlcnRhaW4gdG8gdGhlIG51bWJlciBvZiBDT1ZJRC0xOSBjYXNlcyBpbiBjb3VudHJpZXMgb3ZlciB0aW1lLiBXZSByZW5hbWUgdG8gY29sdW1ucyB0byBkZXNjcmlwdGl2ZSB0aXRsZXMsIGFuZCB3ZSBjb252ZXJ0IHZhbHVlcyB0byB1c2FibGUgZm9ybS4gCgpgYGB7cn0KVGlkeUNPVklEIDwtIENPVklEICU+JQogIHJlbmFtZShjb3VudHJ5ID0gdG90YWwuY292aWQuY2FzZXMuZGVhdGhzLnBlci5taWxsaW9uICkgJT4lCiAgcmVuYW1lKCBjb2RlID0gWCApICU+JQogIHJlbmFtZShkYXRlID0gWC4xICkgJT4lCiAgcmVuYW1lKGNhc2VzUGVyTWlsbGlvbiA9IFguMykgJT4lCiAgZmlsdGVyKHJvd19udW1iZXIoKSA+IDEpICU+JQogIHN1YnNldChzZWxlY3QgPSBjKDEsMiwzLDUpKSAlPiUKICBtdXRhdGUoIGNvdW50cnkgPSBhcy5jaGFyYWN0ZXIoY291bnRyeSkgKSAlPiUgIAogIG11dGF0ZSggY29kZSA9IGFzLmNoYXJhY3Rlcihjb2RlKSApICU+JQogIG11dGF0ZShkYXRlID0gbWR5KGRhdGUpKSAlPiUKICBtdXRhdGUoY2FzZXNQZXJNaWxsaW9uID0gYXMuaW50ZWdlcihjYXNlc1Blck1pbGxpb24pIC0gMSkKCgpgYGAKClRoZSBUaWR5IENPVklEIGRhdGFzZXQgZm9yIG91ciBhbmFseXNpcy4KYGBge3J9ClRpZHlDT1ZJRAoKYGBgCgpFYWNoIGluc3RhbmNlIGluIFRpZHlDT1ZJRCByZXByZXNlbnRzIGEgZGlmZmVyZW50IGRheSBpbiBhIGNvdW50cnkncyBwcm9ncmVzc2lvbiB0aHJvdWdoIENPVklELTE5LiAgSXQgcHJvdmlkZXMgdGhlIGNvdW50cnkgY29kZSAod2hpY2ggd2lsbCBiZSBsYXRlciB1dGlsaXplZCB0byBhc3NpZ24gY29udGluZW50IGNhdGVnb3JpemF0aW9uKSwgdGhlIGRhdGUsIGFuZCB0aGUgdG90YWwgY2FzZXMgcGVyIG1pbGxpb24gdXAgYXQgdGhhdCBkYXRlLgoKCiMjIyBXcmFuZ2xpbmcgb2YgY291bnRyeVJlZ2lvbnMgRGF0YXNldAoKV2Ugd2lsbCBleHRyYWN0IHRoZSBJU08zIGNvdW50cnkgY29kZSBhbmQgY29udGluZW50IGZyb20gdGhlIGNvdW50cnlSZWdpb25zIGRhdGEuIFNpbmNlIG5hbWluZyBjb252ZW50aW9ucyBvZiBjb3VudHJpZXMgaXMgdmFyaWF0ZSwgdGhlIElTTzMgY291bnRyeSBjb2RlIGFsbG93cyB1cyBhIHN0YW5kYXJkaXplZCBkZW1hcmNhdGlvbiBvZiBjb3VudHJ5IHdpdGggd2hpY2ggdG8gam9pbiB3aXRoIG90aGVyIGRhdGEgdGFibGVzLgoKYGBge3J9CkxhYmVscyA8LQogIGNvdW50cnlSZWdpb25zICU+JQogIHN1YnNldChzZWxlY3QgPSBjKCJJU08zIiwgIlJFR0lPTiIpKSAlPiUKICByZW5hbWUoY29udGluZW50ID0gUkVHSU9OKQoKTGFiZWxzCgpgYGAKCgojIyMgRGF0YSBFeHRyYWN0aW9uIG9mIENvdW50cnlEYXRhIERhdGFzZXQKCldlIHdpbGwgc2VsZWN0IHRoZSBhc3BlY3RzIG9mIENvdW50cnlEYXRhIHJlbGV2YW50IHRvIG91ciBhbmFseXNpcy4gVGhlc2UgYXR0cmlidXRlcyBhcmU6IGFyZWEgKHNxIGttKSBhbmQgcG9wIChudW1iZXIgb2YgcGVvcGxlKS4gRnJvbSB0aGVzZSBhdHRyaWJ1dGVzIHdlIGNhbGN1bGF0ZSB0aGUgY291bnRyeSdzIHBvcGRlbnNpdHkgKHBlcnNvbi9zcSBrbSkuCgpgYGB7cn0KClJlbGV2YW50Q291bnRyeURhdGEgPC0KICBDb3VudHJ5RGF0YSAlPiUKICBzdWJzZXQoc2VsZWN0ID0gYygxLDIsMykpICU+JQogIG11dGF0ZShwb3BkZW5zaXR5ID0gcG9wL2FyZWEpCgpSZWxldmFudENvdW50cnlEYXRhCmBgYAoKIyMjIEpvaW5pbmcgRGF0YSAmIFJlbGV2YW50IFZhcmlhYmxlIFN5bnRoZXNpcwoKQXQgdGhpcyBwb2ludCwgd2Ugam9pbiB0aGUgdGlkaWVkIENPVklEIGRhdGEgc2V0IHdpdGggdGhlIGV4dHJhY3RlZCBDb3VudHJ5RGF0YSBzZXQgc3VjaCB0aGF0IGVhY2ggY2FzZSByZXByZXNlbnRzIGEgZGlmZmVyZW50IGRheSBpbiBhIGNvdW50cnkncyBwcm9ncmVzc2lvbiB0aHJvdWdoIENPVklELTE5LCBwcm92aWRpbmcgdGhlIHNwZWNpZmljIGNvdW50cnksIGRhdGUsIHRvdGFsIGNhc2VzIHBlciBtaWxsaW9uIHVwIGF0IHRoYXQgZGF0ZSwgdGhlIGFyZWEgb2YgdGhlIGNvdW50cnkgKHNxIGttKSwgdGhlIHBvcHVsYXRpb24gb2YgdGhlIGNvdW50cnksIHRoZSBwb3B1bGF0aW9uIGRlbnNpdHkgb2YgdGhlIGNvdW50cnltIHRoZSB0b3RhbCBudW1iZXIgb2YgY2FzZXMgKGRlcml2ZWQgYnkgbXVsdGlwbHlpbmcgYSBjb3VudHJ5J3MgY2FzZXNQZXJNaWxsaW9uIGJ5IHRoZSBwb3B1bGF0aW9uIChpbiBtaWxsaW9ucykpLCBhbmQgdGhlIGNvbnRpbmVudCBjYXRlZ29yaXphdGlvbi4KCmBgYHtyfQoKQ09WSURHcm93dGggPC0KICBpbm5lcl9qb2luKFRpZHlDT1ZJRCwgUmVsZXZhbnRDb3VudHJ5RGF0YSwgYnkgPSBjKCJjb3VudHJ5IikpICU+JQogIG11dGF0ZSgiY2FzZXMiID0gKGNhc2VzUGVyTWlsbGlvbiAqIHJvdW5kKHBvcC8xMDAwMDAwLCBkaWdpdHMgPSAwKSkpCgpDT1ZJREdyb3d0aCA8LQogIENPVklER3Jvd3RoICU+JQogIGxlZnRfam9pbihMYWJlbHMsIGJ5ID0gYygiY29kZSIgPSAiSVNPMyIpKQoKQ09WSURHcm93dGggPC0KICBDT1ZJREdyb3d0aCAlPiUKICBzdWJzZXQoc2VsZWN0ID0gYygxLCAzLCA0LCA1LCA2LCA3LCA4LCA5KSkKCkNPVklER3Jvd3RoCmBgYAoKIyMjIENyZWF0aW9uIG9mIG5ldyBEYXRhIFRhYmxlOiBGaXJzdEluc3RhbmNlCgpUaGlzIG5ldyBkYXRhIHRhYmxlIHJlY29yZHMgdGhlIGZpcnN0IGRhdGUgdGhhdCBhIGNvdW50cnkgcmVjb3JkZWQgYSBub256ZXJvIG51bWJlciBvZiBDT1ZJRC0xOSBjYXNlcy4gVGhpcyBkYXRhZ3JhcGggd2lsbCBoZWxwIHVzIHZpc3VhbGl6ZSB3aGVuIGNvdW50cmllcyBmaXJzdCBiZWNhbWUgaW5mZWN0ZWQuCmBgYHtyfQoKRmlyc3RJbnN0YW5jZSA8LQogIENPVklER3Jvd3RoICU+JQogIGZpbHRlcihjYXNlcyAhPSAwKSAlPiUKICBncm91cF9ieShjb3VudHJ5LCBjb250aW5lbnQpICU+JQogIHN1bW1hcmlzZShiZWdpbm5pbmdvZnNwcmVhZCA9IG1pbihkYXRlKSkKICAKRmlyc3RJbnN0YW5jZQoKCmBgYAoKCgojIyMgQ3JlYXRpb24gb2YgbmV3IERhdGEgVGFibGU6IERhaWx5U3ByZWFkCgpUaGUgRGFpbHlTcHJlYWQgZGF0YSBmcmFtZSB1dGlsaXplcyB0aGUgQ09WSURHcm93dGggZGF0YSBhbG9uZyB3aXRoIHRoZSBiZWdpbm5pbmdvZnNwcmVhZCB2YXJpYWJsZSAod2hpY2ggd2FzIGRlcml2ZWQgaW4gdGhlIEZpcnN0SW5zdGFuY2UgdGFibGUpIGluIG9yZGVyIHRvIGNhbGN1bGF0ZSBhIHN0cmFpZ2h0LWxpbmUgYXBwcm94aW1hdGlvbiBvZiB0aGUgZGFpbHkgc3ByZWFkIG9mIENPVklELTE5LCBhdmVyYWdpbmcgY2FzZXMgb3ZlciB0aW1lIGZyb20gdGhlIGZpcnN0IGRheSBhIGNvdW50cnkgd2FzIGluZmVjdGVkIHRvIHRoZSBtb3N0IHJlY2VudCBkYXRlIGluIHRoZSBkYXRhIHRhYmxlIChBcHJpbCA1IDIwMjApLiBJZiBhIGNvdW50cnkgaGFzIG5vdCBiZWVuIGluZmVjdGVkLCB0aGUgZGFpbHlzcHJlYWQgaXMgc2V0IHRvIDAuCgpgYGB7cn0KCkRhaWx5U3ByZWFkIDwtCiAgbGVmdF9qb2luKENPVklER3Jvd3RoLCBGaXJzdEluc3RhbmNlLCBieSA9IGMoImNvdW50cnkiKSkgJT4lCiAgZmlsdGVyKGRhdGUgPT0gIjIwMjAtMDQtMDUiKSAlPiUKICBtdXRhdGUoZGF5c2VsYXBzZWQgPSBkYXRlIC0gYmVnaW5uaW5nb2ZzcHJlYWQpICU+JQogIG11dGF0ZShkYWlseXNwcmVhZCA9IGNhc2VzIC8gYXMubnVtZXJpYyhkYXlzZWxhcHNlZCkgKSAlPiUKICBtdXRhdGUoZGFpbHlzcHJlYWRwZXJtaWxsaW9uID0gY2FzZXNQZXJNaWxsaW9uIC8gYXMubnVtZXJpYyhkYXlzZWxhcHNlZCkgKSAlPiUKICBzdWJzZXQoc2VsZWN0ID0gYygiY291bnRyeSIsICJiZWdpbm5pbmdvZnNwcmVhZCIsICJkYWlseXNwcmVhZCIsICJkYWlseXNwcmVhZHBlcm1pbGxpb24iKSkKCkRhaWx5U3ByZWFkJGRhaWx5c3ByZWFkW2lzLm5hKERhaWx5U3ByZWFkJGRhaWx5c3ByZWFkKV0gPC0gMApEYWlseVNwcmVhZCRkYWlseXNwcmVhZHBlcm1pbGxpb25baXMubmEoRGFpbHlTcHJlYWQkZGFpbHlzcHJlYWRwZXJtaWxsaW9uKV0gPC0gMAoKCkRhaWx5U3ByZWFkCmBgYAoKCiMjIyBDb21wcmVoZW5zaXZlIERhdGEgVGFibGU6IENPVklERmluYWwKCgpKb2luaW5nIHRoZSBncm93dGgtY2FsY3VsYXRlZCBDT1ZJRCBkYXRhIHNldCB3aXRoIHRoZSBEYWlseVNwcmVhZCBzdGF0aXN0aWNzIGFsbG93cyB1cyBvdXIgY29tcHJlaGVuc2l2ZSBkYXRhIGZyYW1lIHdpdGggd2hpY2ggd2Ugd2lsbCBjb25kdWN0IG91ciBhbmFseXNpcy4gV2l0aGluIHRoaXMgZnJhbWUsIGVhY2ggY2FzZSByZXByZXNlbnRzIGEgZGlmZmVyZW50IGRheSBpbiBhIGNvdW50cnkncyBwcm9ncmVzc2lvbiB0aHJvdWdoIENPVklELTE5LCBwcm92aWRpbmcgdGhlIHNwZWNpZmljIGNvdW50cnksIGRhdGUsIHRvdGFsIGNhc2VzIHBlciBtaWxsaW9uIHVwIGF0IHRoYXQgZGF0ZSwgdGhlIGFyZWEgb2YgdGhlIGNvdW50cnkgKHNxIGttKSwgdGhlIHBvcHVsYXRpb24gb2YgdGhlIGNvdW50cnksIHRoZSBwb3B1bGF0aW9uIGRlbnNpdHkgb2YgdGhlIGNvdW50cnltIHRoZSB0b3RhbCBudW1iZXIgb2YgY2FzZXMgKGRlcml2ZWQgYnkgbXVsdGlwbHlpbmcgYSBjb3VudHJ5J3MgY2FzZXNQZXJNaWxsaW9uIGJ5IHRoZSBwb3B1bGF0aW9uIChpbiBtaWxsaW9ucykpLCBjb250aW5lbnQgY2F0ZWdvcml6YXRpb24sIGRhdGUgd2hpY2ggdGhlIHNwcmVhZCBvZiBDT1ZJRC0xOSBiZWdhbiwgdGhlIGF2ZXJhZ2UgZGFpbHkgc3ByZWFkIG9mIENPVklELTE5LCBhbmQgdGhlIGF2ZXJhZ2UgZGFpbHkgc3ByZWFkIG9mIENPVklELTE5IHBlciBtaWxsaW9uIG9mIHBvcHVsYXRpb24uCgoKYGBge3J9CgpDT1ZJREZpbmFsIDwtCiAgbGVmdF9qb2luKENPVklER3Jvd3RoLCBEYWlseVNwcmVhZCwgYnkgPSBjKCJjb3VudHJ5IikpCgoKYGBgCgoKCmBgYHtyfQpDT1ZJREZpbmFsCgpgYGAKCgoKCgoKCgojIyBEYXRhIFZpc3VhbGl6YXRpb24KCgojIyMgT3ZlcmFsbCBHcm93dGggb2YgQ09WSUQtMTkgT3ZlciBUaW1lCmBgYHtyfQoKQ09WSURGaW5hbCAlPiUKICBncm91cF9ieShkYXRlKSAlPiUKICBzdW1tYXJpc2UodG90YWxjYXNlcyA9IHN1bShjYXNlcykpICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSB0b3RhbGNhc2VzKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIkRhdGUiKSArCiAgeWxhYigiQ09WSUQtMTkgQ2FzZXMiKQoKYGBgClRoaXMgZ3JhcGggZGVtb25zdHJhdGVzIHRoZSBleHBvbmVudGlhbCBncm93dGggdHJlbmQgb2YgQ09WSUQtMTkgZ2xvYmFsbHkuIFRoZXJlIGlzIGEgc3Ryb25nIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHByb2dyZXNzaW9uIG9mIHRpbWUgYW5kIHRoZW4gbnVtYmVyIG9mIENPVklELTE5IGNhc2VzIHdvcmxkd2lkZS4KCgojIyMgQ29udGluZW50YWwgR3Jvd3RoIG9mIENPVklELTE5IE92ZXIgVGltZQoKYGBge3J9CgpuYS5vbWl0KENPVklERmluYWwpICU+JQogIGdyb3VwX2J5KGRhdGUsIGNvbnRpbmVudCkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gdG90YWxjYXNlcykpICsgCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF93cmFwKH5jb250aW5lbnQpICsKICB4bGFiKCJEYXRlIikgKwogIHlsYWIoIkNPVklELTE5IENhc2VzIikKYGBgClRoaXMgZ3JhcGggc2hvd3MgdGhlIGdyb3d0aCBvZiBDT1ZJRC0xOSBjYXNlcyBvdmVyIHRpbWUsIGZhY2V0ZWQgYnkgY29udGluZW50LiBUaGUgZ2xvYmFsIGV4cG9uZW50aWFsIHRyZW5kIGlzIG1vc3QgdmlzaWJsZSBpbiB0aGUgb3JpZ2luIGNvbnRpbmVudCBvZiBBc2lhLCBidXQgdGhlIHBvc2l0aXZlIGNvcnJlbGF0aW9uIG9mIENPVklELTE5IG92ZXIgdGltZSBpcyB2aXNpYmxlIGluIGVhY2ggY29udGluZW50cy4KCiMjIyBJbmZlY3Rpb24gb2YgQ09WSUQtMTkgaW50byBjb3VudHJpZXMgb3ZlciB0aW1lCmBgYHtyfQoKbmEub21pdChGaXJzdEluc3RhbmNlKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBiZWdpbm5pbmdvZnNwcmVhZCwgZmlsbCA9IGNvbnRpbmVudCkpICsKICBnZW9tX2RvdHBsb3Qoc3RhY2tncm91cHMgPSBUUlVFLCBiaW53aWR0aCA9IDEsIGJpbnBvc2l0aW9ucz0iYWxsIikgKwogIHhsYWIoIkNvdW50cnkncyBGaXJzdCBDYXNlIG9mIENPVklELTE5IikgKwogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgClRoaXMgZ3JhcGggc2hvd3MgdGhlIHByb2dyZXNzaW9uIG9mIHRoZSBDT1ZJRC0xOSBzcHJlYWQgYWNyb3NzIGNvbnRpbmVudHMuIEFzIHN1cHBvcnRlZCBhbmQgY29uZ3J1ZW50IHdpdGggdGhlIGZhY2V0ZWQgZ3JhcGggb2YgY29udGluZW50YWwgZ3Jvd3RoIG92ZXIgdGltZSwgQXNpYSB3YXMgdGhlIGZpcnN0IGNvbnRpbmVudCB0byBiZSBpbmZlY3RlZCwgZm9sbG93ZWQgYnkgTm9ydGggQW1lcmljYSBhbmQgRXVyb3BlLiBJbiBsYXRlIEZlYnJ1YXJ5LCBTb3V0aCBBbWVyaWNhIGFuZCBBZnJpY2EgYmVnYW4gdG8gYmVjb21lIGluZmVjdGVkLCBhbmQgQXVzdHJhbGlhIHdhcyBhYmxlIHRvIGlzb2xhdGUgdW50aWwgbWlkIE1hcmNoLiBXaGVyZSBjb250aW5lbnRhbCBkYXRhcG9pbnRzIHNob3cgZGVuc2l0eSBhbGxpZ25zIHdpdGgsIGluIHRoZSBncmFwaGljIGFib3ZlLCB3aGVyZSB0aGUgY29udGluZW50cyBleHBlcmllbmNlIGdyZWF0ZXN0IHBlcmlvZHMgb2YgZ3Jvd3RoLgoKCgoKIyMjIFdoaWNoIGNvdW50cmllcyBoYXZlIHRoZSBoaWdoZXN0IGluZmVjdGlvbiByYXRlcz8KCgpgYGB7cn0KICAKQ09WSURGaW5hbCAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBzdW1tYXJpc2UoZGFpbHlzcHJlYWQgPSBtZWFuKGRhaWx5c3ByZWFkKSkgJT4lCiAgYXJyYW5nZShkZXNjKGRhaWx5c3ByZWFkKSkgJT4lCiAgaGVhZCgyMCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCBkZXNjKGRhaWx5c3ByZWFkKSksIHk9IGRhaWx5c3ByZWFkKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSAnc3RhY2snLCB3aWR0aD0uOSkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCBoanVzdCA9IDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKSArCiAgeWxhYigiQXZlcmFnZSBOdW1iZXIgSW5mZWN0ZWQgUGVyIERheSIpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCgoKCmBgYApUaGlzIGdyYXBoaWMgZGVtb25zdHJhdGVzIHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgaGlnaGVzdCBpbmZlY3Rpb24gcmF0ZXMtLSB0aG9zZSBtb3N0IHNpZ25pZmljYW50IG9mIHdoaWNoIGFyZSBDaGluYSwgSW5kaWEsIEluZG9uZXNpYSwgYW5kIHRoZSBVbml0ZWQgU3RhdGVzLCBjbG9zZWx5IGZvbGxvd2VkIGJ5IEJyYXppbCwgYWZ0ZXIgd2hpY2ggdGhlIHJhdGUgb2YgaW5mZWN0aW9uIHRhcGVycyBvZmYgdG8gYSBjb21wYXJhdGl2ZWx5IHNpbWlsYXIgcmF0ZS4KCiMjIyBDb21wYXJlIHRoaXMgdG8gd2hpY2ggY291bnRyaWVzIGhhdmUgdGhlIGhpZ2hlc3QgcG9wdWxhdGlvbnMKCmBgYHtyfQoKQ09WSURGaW5hbCAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBzdW1tYXJpc2UocG9wID0gbWVhbihwb3ApKSAlPiUKICBhcnJhbmdlKGRlc2MocG9wKSkgJT4lCiAgaGVhZCgyMCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCBkZXNjKHBvcCkpLCB5PSBwb3ApKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICdzdGFjaycsIHdpZHRoPS45KSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gNjAsIGhqdXN0ID0gMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBGQUxTRSkpICsKICB5bGFiKCJQb3B1bGF0aW9uIikgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkKCgpgYGAKV2Ugc2VlIGEgc2ltaWxhciB0cmVuZCBoZXJlLCBpbiB0aGF0IHRoZSBjb3VudHJpZXMgb2YgdG9wIHBvcHVsYXRpb24gKGluIHNsaWdodGx5IGRpZmZlcmVudCBvcmRlcikgY29uc2lzdCBvZiBDaGluYSwgSW5kaWEsIEluZG9uZXNpYSwgdGhlIFVuaXRlZCBTdGF0ZXMsIGFuZCBjbG9zZWx5IHRyYWlsaW5nIEJyYXppbCwgYWZ0ZXIgd2hpY2ggcG9wdWxhdGlvbiBzZWVtcyB0byB0YXBlciBvZmYgdG8gcmVsYXRpdmVseSBzaW1pbGFyIGxldmVscy4KCiMjIyBMZXQncyB2aXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHBvcHVsYXRpb24gYW5kIENPVklELTE5IHNwcmVhZCBvbiB0aGUgc2FtZSBkYXRhIGZyYW1lLi4uIHdpdGggYW4gYXdhcmVuZXNzIG9mIHRoZSBjb250aW5lbnRhbCBkaXN0cmlidXRpb24KCgpgYGB7cn0KCm5hLm9taXQoQ09WSURGaW5hbCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcG9wLCB5ID0gZGFpbHlzcHJlYWQsIGNvbG9yID0gY29udGluZW50KSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIlBvcHVsYXRpb24gb2YgQ291bnRyeSIpICsKICB5bGFiKCJBdmVyYWdlIE51bWJlciBJbmZlY3RlZCBQZXIgRGF5IikKCgoKYGBgClRoaXMgZGF0YWZyYW1lIGNsZWFybHkgZGVtb25zdHJhdGVzIHRoZSBzdHJvbmcgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBhIGNvdW50cnkncyBwb3B1bGF0aW9uIGFuZCBhdmVyYWdlIG51bWJlciBpbmZlY3RlZCBwZXIgZGF5LCBhcyBzdXBwb3J0ZWQgYnkgb3VyIGFuYWx5c2lzIG9mIHRoZSBwcmV2aW91cyB0d28gZ3JhcGhpY3MuIFdoaWxlIG1vc3QgY291bnRyaWVzIG9mIHRoZSB3b3JsZCB0cmFpbCB3aXRoIHVuZGVyIDEwLDAwMCBpbmZlY3RlZCBwZXIgZGF5LCB0aGUgNSBjb3VudHJpZXMgd2l0aCB0aGUgaGlnaGVzdCBwb3B1YWx0aW9uIGluIHRoZSBkYXRhIHNldCBoYXZlIG92ZXIgMTUsMDAwIC0gdXAgdG8gb3ZlciA1MCwwMDAtIGFuZCBhcmUgZmFyIHNlcGFyYXRlZCBmcm9tIHRoZSByZXN0IG9mIHRoZSBwYWNrLiAgUG9wdWxhdGlvbiwgd2hpbGUgbm90IGEgZGlyZWN0IGZhY3RvciBjb250cmlidXRpbmcgdG8gdGhlIGxldmVsIG9mIGRldmVsb3BtZW50IG9mIGEgY291bnRyeSwgaXMgYSBkZWNlbnQgaW5kaWNhdG9yIG9mIHRoZSByYXRlIG9mIGluZmVjdGlvbi4KCgojIyMgRG9lcyB0aGUgcmVsYXRpb25zaGlwIGhvbGQgdXAgYWZ0ZXIgcmVtb3ZpbmcgdGhlIGxhcmdlc3Qgb3V0bGllcnMgKENoaW5hIGFuZCBJbmRpYSk/CgojIyMgRG9lcyB0aGUgcG9zaXRpdmUgcmVsYXRpb25zaGlwIGhvbGQgdXAgYWNyb3NzIGFsbCBjb250aW5lbnRzPwpgYGB7cn0KCm5hLm9taXQoQ09WSURGaW5hbCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcG9wLCB5ID0gZGFpbHlzcHJlYWQsIGNvbG9yID0gY29udGluZW50KSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHhsaW0oMCw1MDAwMDAwMDApICsKICB5bGltKDAsIDQwMDAwKSArCiAgeGxhYigiUG9wdWxhdGlvbiBvZiBDb3VudHJ5IikgKwogIHlsYWIoIkF2ZXJhZ2UgTnVtYmVyIEluZmVjdGVkIFBlciBEYXkiKSArCiAgc3RhdF9zbW9vdGgobWV0aG9kID0gbG0pIAoKCgpgYGAKUmVtb3ZpbmcgdGhlIGxhcmdlc3Qgb3V0bGllcnMgb2YgcG9wdWxhdGlvbiBhbmQgbnVtYmVyIGluZmVjdGVkLCB0aGUgcG9pdGl2ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhdmVyYWdlIG51bWJlciBpbmZlY3RlZCBhbmQgcG9wdWxhdGlvbiBzdGlsbCBob2xkczsgZm9yIGVhY2ggY29udGluZW50LCB0aGUgdHJlbmRzIGFyZSB2ZXJ5IGNsZWFybHkgdXB3YXJkIHNsb3BpbmcuCgoKIyMjIEEgcHJldmFpbGluZyBleHBsYW5hdGlvbiBmb3IgdGhlIHNwcmVhZCBvZiBDT1ZJRC0xOSBpcyBzb2NpYWwgY2xvc2VuZXNzLCB0aGVyZWZvcmUsIHdlIGh5cG90aGVzaXplIHRoYXQgY291bnRyaWVzIHdpdGggdGhlIGhpZ2hlc3QgcG9wdWxhdGlvbiBkZW5zaXR5IHdpbGwgaGF2ZSB0aGUgaGlnaGVzdCBwcm9wb3J0aW9uYWwgcmF0ZXMgb2YgaW5mZWN0aW9uLiBUbyBtZWFzdXJlIHRoZSBwcm9wb3J0aW9uYWwgcmF0ZXMgb2YgaW5mZWN0aW9uLCBpdCBpcyBlc3NlbnRpYWwgdG8gdXNlIGEgc3RhbmRhcmRpemVkIG1ldHJpYywgc3VjaCB0aGF0IHRoZSBkYXRhIGlzIG5vdCBza2V3ZWQgdG93YXJkcyB0aGUgY291bnRyaWVzIHdpdGggc2ltcGx5IHRoZSBtb3N0IHBlb3BsZS4gVGhlcmVmb3JlLCB3ZSB3aWxsIGFuYWx5emUgdGhlIHZhcmlhYmxlICJwb3B1bGF0aW9uIHBlciBtaWxsaW9uIGluZmVjdGVkIHBlciBkYXkiLCB3aGljaCBjYXB0dXJlcyBhIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwZXJjZW50YWdlIG9mIGEgY291bnRyeSdzIHBvcHVsYXRpb24gdGhhdCBpcyBlZmZlY3RpdmUuIElmIG91ciBoeXBvdGhlc2lzIGlzIGNvcnJlY3QsIHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgaGlnaGVzdCBwb3B1bGF0aW9uIHBlciBtaWxsaW9uIGluZmVjdGVkIHBlciBkYXkgd2lsbCBiZSB0aG9zZSB3aXRoIHRoZSBoaWdoZXN0IHBvcHVsYXRpb24gZGVuc2l0eS4KCgojIyMgV2hpY2ggY291bnRyaWVzIGhhdmUgdGhlIGhpZ2hlc3QgaW5mZWN0aW9uIHJhdGVzIHBlciBtaWxsaW9uPwoKCmBgYHtyfQogIApDT1ZJREZpbmFsICU+JQogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIHN1bW1hcmlzZShkYWlseXNwcmVhZHBlcm1pbGxpb24gPSBtZWFuKGRhaWx5c3ByZWFkcGVybWlsbGlvbikpICU+JQogIGFycmFuZ2UoZGVzYyhkYWlseXNwcmVhZHBlcm1pbGxpb24pKSAlPiUKICBoZWFkKDIwKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIGRlc2MoZGFpbHlzcHJlYWRwZXJtaWxsaW9uKSksIHk9IGRhaWx5c3ByZWFkcGVybWlsbGlvbikpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gJ3N0YWNrJywgd2lkdGg9LjkpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGUgPSA2MCwgaGp1c3QgPSAxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IEZBTFNFKSkgKwogIHlsYWIoIlBvcHVsYXRpb24gUGVyIE1pbGxpb24gSW5mZWN0ZWQgUGVyIERheSIpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCgoKCmBgYApBY2NvcmRpbmcgdGhlIHRoaXMgZ3JhcGgsIHRob3NlIHdpdGggdGhlIGhpZ2hlc3QgaW5mZWN0aW9uIHJhdGVzIHdpdGggdGhlIGNvbmZvdW5kaW5nIGZhY3RvciBvZiBwb3B1bGF0aW9uIHJlbW92ZWQgKHNpbmNlIGl0IGlzIHBvcHVsYXRpb24gcGVyIG1pbGxpb24sIGl0IGhhcyBiZWVuIGFkanVzdGVkIHRvIHB1dCBhbGwgY291bnRyaWVzIG9uIG9uZSBzY2FsZSkgYXJlIEd1aW5lYS1CaXNzYXUsIEJvdHN3YW5hLCBFcml0cmVhLCBFbCBTYWx2YWRvciwgYW5kIFB1ZXJ0byBSaWNvLgoKIyMjIFdoaWNoIGNvdW50cmllcyBoYXZlIHRoZSBoaWdoZXN0IHBvcHVsYXRpb24gZGVuc2l0eT8KCmBgYHtyfQogIApDT1ZJREZpbmFsICU+JQogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIHN1bW1hcmlzZShwb3BkZW5zaXR5ID0gbWVhbihwb3BkZW5zaXR5KSkgJT4lCiAgYXJyYW5nZShkZXNjKHBvcGRlbnNpdHkpKSAlPiUKICBoZWFkKDIwKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIGRlc2MocG9wZGVuc2l0eSkpLCB5PSBwb3BkZW5zaXR5KSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSAnc3RhY2snLCB3aWR0aD0uOSkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCBoanVzdCA9IDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKSArCiAgeWxhYigiUG9wdWxhdGlvbiBEZW5zaXR5IChwZW9wbGUvc3Ega20pIikgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkKCgoKYGBgCkFjY29yZGluZyB0aGUgdGhpcyBncmFwaCwgdGhvc2Ugd2l0aCB0aGUgaGlnaGVzdCBwb3B1bGF0aW9uIGRlbnNpdHkgKG51bWJlciBvZiBwZW9wbGUgcGVyIHNxdWFyZSBraWxvbWV0ZXIpIGFyZSBNb25hY28sIFNpbmdhcG9yZSwgYW5kIEdpYnJhbHRhci4KCgoKIyMjIElzIHRoZXJlIGEgdmlzaWJsZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZXNlIGF0dHJpYnV0ZXM/CgoKYGBge3J9Cm5hLm9taXQoQ09WSURGaW5hbCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcG9wZGVuc2l0eSwgeSA9IGRhaWx5c3ByZWFkcGVybWlsbGlvbikpICsKICBnZW9tX3BvaW50KCkgCmBgYApPbiB0aGlzIGdyYXBoLCBpdCBpcyBjaGFsZW5naW5nIHRvIHNlZSBhIGNsZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHBvcHVsYXRpb24gZGVuc2l0eSBhbmQgZGFpbHkgc3ByZWFkIG9mIENPVklELTE5IHBlciBtaWxsaW9uLiAgRm9yIHRoZSBzYWtlIG9mIGNvbXByZWhlbnNpdmUgYW5hbHlzaXMsIHdlIHdpbGwgZnVydGhlciBkaXZpZGUgdGhlIGluZm9ybWF0aW9uLgoKIyMjIFdoYXQgaWYgZmFjZXRlZCBieSBjb250aW5lbnQ/CgpgYGB7cn0KbmEub21pdChDT1ZJREZpbmFsKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwb3BkZW5zaXR5LCB5ID0gZGFpbHlzcHJlYWRwZXJtaWxsaW9uKSkgKwogIGdlb21fcG9pbnQoKSArIAogIGZhY2V0X3dyYXAofmNvbnRpbmVudCkgKyAKICB4bGltKDAsMTUwMCkKCmBgYApBZ2FpbiwgaXQgaXMgaGFyZCB0byBzZWUgYSBwZXJmZWN0IGNvcnJlbGFpdG9uIGhlcmUuICBJbiBnZW5lcmFsLCBhbGwgdGhlIGdyYXBocyBzaG93IGxpdHRsZSB0byBubyBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBwb3B1bGF0aW9uIGRlbnNpdHkgYW5kIHRoZSBkYWlseSBzcHJlYWQgcGVyIG1pbGxpb24uCgoKIyMgRXh0ZW5kZWQgQ29tcGFyYXRpdmUgQW5hbHlzaXMgLSBDb3VudHJ5IENvbXBhcmlzb24gRnVuY3Rpb24KCgojIyMgRWFzeSB0byBUcmF2ZXJzZS0tIFdpZGUgQ291bnRyaWVzCgpgYGB7cn0KCldpZGVDb3VudHJpZXMgPC0KICBDT1ZJREZpbmFsICU+JQogIHN1YnNldChzZWxlY3QgPSBjKCJjb3VudHJ5IiwgImRhdGUiLCAiY2FzZXMiKSkgJT4lCiAgc3ByZWFkKGtleSA9IGRhdGUsIHZhbHVlID0gY2FzZXMpCgpXaWRlQ291bnRyaWVzW2lzLm5hKFdpZGVDb3VudHJpZXMpXSA8LSAwCgpXaWRlQ291bnRyaWVzCgpgYGAKCiMjIyBjb21wYXJlQ09WSUQoKSBkZWZpbml0aW9uCgpgYGB7cn0KCmNvbXBhcmVDT1ZJRCA8LSBmdW5jdGlvbihjb3VudHJ5QSwgY291bnRyeUIpIHsKICAKICAgIEEgPC0KICAgIFdpZGVDb3VudHJpZXMgJT4lCiAgICBmaWx0ZXIoY291bnRyeSA9PSBjb3VudHJ5QSkKICAKICBCIDwtCiAgICBXaWRlQ291bnRyaWVzICU+JQogICAgZmlsdGVyKGNvdW50cnkgPT0gY291bnRyeUIpCgogIEEgPC0KICAgIEEgJT4lCiAgICBnYXRoZXIoa2V5ID0gZGF0ZSwgdmFsdWUgPSBjb3VudCkgJT4lCiAgICBmaWx0ZXIocm93X251bWJlcigpID4gMSkgJT4lCiAgICBtdXRhdGUoZGF0ZSA9IGx1YnJpZGF0ZTo6eW1kKGRhdGUpKSAlPiUKICAgIG11dGF0ZShjb3VudCA9IGFzLm51bWVyaWMoY291bnQpKSAlPiUKICAgIG11dGF0ZShjb3VudHJ5ID0gY291bnRyeUEpCiAgCiAgQiA8LQogICAgQiAlPiUKICAgIGdhdGhlcihrZXkgPSBkYXRlLCB2YWx1ZSA9IGNvdW50KSAlPiUKICAgIGZpbHRlcihyb3dfbnVtYmVyKCkgPiAxKSAlPiUKICAgIG11dGF0ZShkYXRlID0gbHVicmlkYXRlOjp5bWQoZGF0ZSkpJT4lCiAgICBtdXRhdGUoY291bnQgPSBhcy5udW1lcmljKGNvdW50KSkgJT4lCiAgICBtdXRhdGUoY291bnRyeSA9IGNvdW50cnlCKQogIAogIAogIEdHIDwtCiAgICByYmluZChBLEIpCiAgCiAgcmV0dXJuKCBnZ3Bsb3QoR0csIGFlcyh4ID0gZGF0ZSwgeSA9IGNvdW50LCBjb2xvciA9IGNvdW50cnkpKSArCiAgICBzdGF0X3Ntb290aChmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsb2VzcyIpICsKICAgICAgeWxhYigiTnVtYmVyIG9mIENPVklELTE5IENhc2VzIikgKwogICAgICB4bGFiKCJEYXRlIikpCiAgCn0KCgoKCmBgYAoKCiMjIyBFeC4gb2YgY29tcGFyZUNPVklEKCkgaW4gdXNlOgoKVGhpcyBmdW5jdGlvbiBhbGxvdyB1cyB0byBjcmVhdGUgYSBkaXJlY3QgY29tcGFyaXNvbiBiZXR3ZWVuIHR3byBjb3VudHJpZXMgYmFzZWQgb24gdGhlIGRhdGUgYW5kIHRoZSBudW1iZXIgb2YgQ09WSUQtMTkgY2FzZXMgaW4gZWFjaCBjb3VudHJ5LiAgVGhpcyB3YXksIHdlIGNhbiBjb21wYXJlIHRoZSBzcHJlYWQgYmV0d2VlbiBuYXRpb25zIGFuZCBpZGVudGlmeSBzaW1pbGFyIHRyZW5kcyBpbiBkaWZmZXJlbnQgcGFydHMgb2YgdGhlIHdvcmxkLgoKYGBge3J9Cgpjb21wYXJlQ09WSUQoIkNoaW5hIiwgIlVuaXRlZCBTdGF0ZXMiKQoKY29tcGFyZUNPVklEKCJKYXBhbiIsICJSdXNzaWEiKQoKY29tcGFyZUNPVklEKCJQdWVydG8gUmljbyIsICJCZWxnaXVtIikKCmBgYAoKCiMjIENvbmNsdXNpb24KClVsdGltYXRlbHksIHRoZSBjb250cmlidXRpbmcgZmFjdG9ycyBvZiB0aGUgc3ByZWFkIG9mIENPVklELTE5IHN0aWxsIHJlbWFpbnMgYSBteXN0ZXJ5IHRvIHVzLiAgV2Ugd2VyZSBhYmxlIHRvIGZpbmQgYSBzdHJvbmcgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcG9wdWxhdGlvbiBvZiBhIGNvdW50cnkgYW5kIHRoZSBzcHJlYWQuICBUaGlzIGluZGljYXRlcyB0aGF0IHRoZSBtb3JlIHBlb3BsZSBhIGNvdW50cnkgaGFzLCB0aGUgbW9yZSBsaWtlbHkgdGhlIGluZmVjdGlvbiBpcyB0byBhZmZlY3QgYSBsYXJnZSBudW1iZXIgb2YgcGVvcGxlLiBIb3dldmVyLCB3ZSBzdHJ1Z2dsZWQgdG8gZmluZCBhIHN0cm9uZyBjb3JyZWxhdGlvbiwgb25jZSBzdGFuZGFyZGl6ZWQgYW5kIGNvbmZvdW5kaW5nIGZhY3RvcnMgd2VyZSByZW1vdmVkLCBiZXR3ZWVuIHRoZSBwb3B1bGF0aW9uIGRlbnNpdHkgb2YgYSBjb3VudHJ5IGFuZCBpdHMgaW5mZWN0aW9uIHJhdGUgcGVyIG1pbGxpb24uIFRoaXMgZG9lcyBub3QgbmVjZXNzYXJpbHkgcHJvdmUgdGhhdCBkZW5zaXR5IG9mIGxpdmluZyBkb2VzIG5vdCBjb250cmlidXRlIHRvIHRoZSBzcHJlYWQgb2YgQ09WSUQtMTktLSBvbmUgZmF1bHQgcHJlc2VudCB3aXRoaW4gdGhpcyBhbmFseXNpcyBpcyB0aGF0IHBvcHVsYXRpb24gZGVuc2l0eSB3YXMgY2FsY3VsYXRlZCBmcm9tIGEgY291bnRyeSdzIGVudGlyZSBsYW5kIGFyZWEsIHdoZXJlYXMgb25seSBhIHNtYWxsIHBvcnRpb24gb2YgdGhpcyBsYW5kIGFyZWEgbWF5IGJlIGluaGFiaXRlZC4gSWYgd2Ugd2VyZSB0byBjb25kdWN0IHRoaXMgYW5hbHlzaXMgYWdhaW4sIHdlIHdvdWxkIHNlZWsgb3V0IGRhdGEgd2hpY2ggcHJvdmlkZXMgdGhlIGluaGFiaXRlZCBsaXZpbmcgYXJlYSBvZiBhIGNvdW50cnkgdG8gbW9yZSBhY2N1cmF0ZWx5IGNhbGN1bGF0ZSBwb3B1bGF0aW9uIGRlbnNpdHkuIEZ1cnRoZXJtb3JlLCBhcyBkZW1vbnN0cmF0ZWQgYnkgdGhlIGdyYXBoaWNzLCBtYW55IGNvdW50cmllcyBoYXZlIGJlZW4gaW5mZWN0ZWQgdmVyeSByZWNlbnRseSwgb3Igbm90IGluZmVjdGVkIGF0IGFsbC4gVGhlIGdyb3d0aCBvZiBjb3VudHJ5IGRlbW9uc3RyYXRlcyBpbiB0aGlzIHNob3J0IHBlcmlvZCBvZiB0aW1lIG1heSBub3QgYmUgaW5kaWNhdGl2ZSBvZiB0aGUgb3ZlcmFsbCBncm93dGggdHJlbmQgdGhhdCBhIGNvdW50cnkgZXhwZXJpZW5jZXMuIEluIHRoZSBmdXR1cmUsIG9uY2Ugd2UgYXJlIG1vcmUgdXBkYXRlZCBhbmQgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCBDT1ZJRC0xOSBpcyByZWxlYXNlZCwgc29tZSBvZiB0aGUgdHJlbmRzIHdoaWNoIHdlIGFyZSBzZWVraW5nIG1heSBiZSBtb3JlIHJlbGV2YW50IG9yIGVhc3kgdG8gZGVmaW5lLiAgSG93ZXZlciwgd2l0aCB0aGUgZGF0YSB3ZSBjdXJyZW50bHkgcG9zc2VzcywgaXQgd2FzIG5vdCBwb3NzaWJsZSB0byBtYWtlIHRoZSBjb25jbHVzaW9uLS0gdGhhdCBwb3B1bGF0aW9uIGRlbnNpdHkgaXMgY29ycmVsYXRlZCB3aXRoIHN0YW5kYXJkaXplZCBDT1ZJRC0xOSBzcHJlYWQtLSB3aXRoIGNvbmZpZGVuY2UuCgoKCgo=